#include "mywidget.h"

#include <QStringList>
#include <QCoreApplication>
#include <QMessageBox>
#include <exception>
#include <stdexcept>
#include <QHeaderView>

/// Parameter: value: vertical scrollbar's position
/// Return:
/// Action: Moves both image viewer's vertical scrollbar
void MyWidget::ver_moved(int value)
{
    _originalImageViewer->move_vertical_scrollbar(value);

    if (_modifiedImageViewer != 0)
        _modifiedImageViewer->move_vertical_scrollbar(value);
}

/// Parameter: value: horizontal scrollbar's position
/// Return:
/// Action: Moves both image viewer's horizontal scrollbar
void MyWidget::hor_moved(int value)
{
    _originalImageViewer->move_horizontal_scrollbar(value);

    if (_modifiedImageViewer != 0)
        _modifiedImageViewer->move_horizontal_scrollbar(value);
}

/// Parameter: parent: Parent widget
/// Return:
/// Action: Constructor
///         Constructs the widget, sets the properties.
MyWidget::MyWidget(QWidget *parent) : QWidget(parent)
{
    _originalPlaceHolder.setMinimumSize(400, 200);
    _modifiedPlaceHolder.setMinimumSize(400, 200);

    _imageSplitter = new QSplitter;
    _mainSplitter = new QSplitter(Qt::Vertical);

    _imageSplitter->addWidget(&_originalPlaceHolder);
    _imageSplitter->addWidget(&_modifiedPlaceHolder);
    _imageSplitter->setHandleWidth(0);

    _mainLayout = new QVBoxLayout;

    QStringList header = (QStringList() << "Width" << "Height" << "Transformation" << "Parallel?" << "ms");

    _table = new QTableWidget(0, 5);
    _table->setHorizontalHeaderLabels(header);
    _table->horizontalHeader()->setStretchLastSection(true);
    _table->setEditTriggers(QAbstractItemView::NoEditTriggers);
    _rows = 0;

    _mainSplitter->addWidget(_imageSplitter);
    _mainSplitter->addWidget(_table);

    _mainLayout->addWidget(_mainSplitter);

    setLayout(_mainLayout);

    _modifiedImageViewer = 0;
    _originalImageViewer = 0;
    _modifiedImage = 0;

    installEventFilter(this);
}

/// Parameter:
/// Return:
/// Action: Destructor
MyWidget::~MyWidget()
{
    delete _mainLayout;
}

/// Parameter: fileName: original image's location
/// Return:
/// Action: Sets the original image
///         Hides the placeholder, and places the image instead of it
///         If a previous image has been transformed, it becomes hidden, and a placeholder is shown.
void MyWidget::set_original(QImage* img)
{
    if (_originalImageViewer == 0)
    {
        _originalImageViewer = new ImageViewer(img);
        int index = _imageSplitter->indexOf(&_originalPlaceHolder);
        _imageSplitter->widget(index)->hide();
    }
    else
    {

        delete _originalImageViewer;
        delete _modifiedImageViewer;
        _modifiedImageViewer = 0;

        _originalImageViewer = new ImageViewer(img);

        int index = _imageSplitter->indexOf(&_modifiedPlaceHolder);
        _imageSplitter->widget(index)->show();
    }

    _imageSplitter->insertWidget(1, _originalImageViewer);

    disconnect(_originalImageViewer, SIGNAL(ver_moved(int)), this, SLOT(ver_moved(int)));
    disconnect(_originalImageViewer, SIGNAL(hor_moved(int)), this, SLOT(hor_moved(int)));

    connect(_originalImageViewer, SIGNAL(ver_moved(int)), this, SLOT(ver_moved(int)));
    connect(_originalImageViewer, SIGNAL(hor_moved(int)), this, SLOT(hor_moved(int)));

    _modifiedImage = 0;
}

/// Parameter: img: modified image to be shown
/// Return:
/// Action: Sets the modified image.
void MyWidget::set_modified(QImage* img)
{
    if (img->isNull())
    {
        _imageSplitter->widget(2)->hide();
        int index = _imageSplitter->indexOf(&_modifiedPlaceHolder);
        _imageSplitter->widget(index)->show();
        _modifiedImage = 0;
        return;
    }

    if (_modifiedImageViewer == 0)
    {
        _modifiedImageViewer = new ImageViewer(img);
        _imageSplitter->widget(2)->hide();
    }
    else
    {
        delete _modifiedImageViewer;
        _modifiedImageViewer = new ImageViewer(img);
    }

    int index = _imageSplitter->indexOf(&_modifiedPlaceHolder);
    _imageSplitter->widget(index)->hide();

    _imageSplitter->insertWidget(2, _modifiedImageViewer);
    _originalImageViewer->zoom_reset();

    disconnect(_modifiedImageViewer, SIGNAL(ver_moved(int)), this, SLOT(ver_moved(int)));
    disconnect(_modifiedImageViewer, SIGNAL(hor_moved(int)), this, SLOT(hor_moved(int)));

    connect(_modifiedImageViewer, SIGNAL(ver_moved(int)), this, SLOT(ver_moved(int)));
    connect(_modifiedImageViewer, SIGNAL(hor_moved(int)), this, SLOT(hor_moved(int)));

    if (_modifiedImage != 0)
        delete _modifiedImage;

    _modifiedImage = new QImage;

    *_modifiedImage = img->copy();

    if (_modifiedImage->isNull())
    {
        std::runtime_error ex("Out of memory");
        throw ex;
    }
}

/// Parameter: info: Informatioun about the transformation
/// Return:
/// Action: Adds information to the table
void MyWidget::add_info(const TransformInfo info)
{
    if (!__canTransform)
    {
        __canTransform = true;
        //QCoreApplication::processEvents(QEventLoop::AllEvents);
        return;
    }

    _rows++;
    _table->setRowCount(_rows);

    QString s;
    if (info._parallel)
        s = "yes";
    else
        s = "no";

    QTableWidgetItem* width = new QTableWidgetItem(QString::number(info._width));
    QTableWidgetItem* height = new QTableWidgetItem(QString::number(info._height));
    QTableWidgetItem* transformation = new QTableWidgetItem(QString::fromStdString(info._transformation));
    QTableWidgetItem* parallel =  new QTableWidgetItem(s);
    QTableWidgetItem* time = new QTableWidgetItem(QString::number(info._time));

    _table->setItem(_rows - 1, 0, width);
    _table->setItem(_rows - 1, 1, height);
    _table->setItem(_rows - 1, 2, transformation);
    _table->setItem(_rows - 1, 3, parallel);
    _table->setItem(_rows - 1, 4, time);
}

/// Parameter: e: wheel event by scrolling
/// Return:
/// Action: Forwards the wheel event to the image viewers
void MyWidget::wheelEvent(QWheelEvent *e)
{
    if (_originalImageViewer != 0)
        _originalImageViewer->wheelEvent(e);

    if (_modifiedImageViewer != 0)
        _modifiedImageViewer->wheelEvent(e);
}

/// Parameter:
/// Return:
/// Action: Zooms in for both image viewers
void MyWidget::zoom_in()
{
    if (_originalImageViewer != 0)
        _originalImageViewer->zoom_in();

    if (_modifiedImageViewer != 0)
        _modifiedImageViewer->zoom_in();
}

/// Parameter:
/// Return:
/// Action: Zooms out for both image viewers
void MyWidget::zoom_out()
{
    if (_originalImageViewer != 0)
        _originalImageViewer->zoom_out();

    if (_modifiedImageViewer != 0)
        _modifiedImageViewer->zoom_out();
}

/// Parameter:
/// Return:
/// Action: Resets zoom for both image viewers
void MyWidget::zoom_reset()
{
    if (_originalImageViewer != 0)
        _originalImageViewer->zoom_reset();

    if (_modifiedImageViewer != 0)
        _modifiedImageViewer->zoom_reset();
}

/// Parameter:
/// Return:
/// Action: The modified image is used for further transformation.
void MyWidget::swap()
{
    if ((_modifiedImage == 0) || (_modifiedImage->isNull()))
    {
        _modifiedImage = 0;
        return;
    }

    _originalImageViewer->change_image(_modifiedImage);
}
